<!--https://www.datazzh.top-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>广东城市房产数据可视化</title>
  <!-- 引入ECharts -->
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="/static/js/echarts.min.js"></script>
  <!-- 引入Font Awesome -->
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#64748b',
            accent: '#f97316',
            neutral: '#f8fafc',
            'neutral-dark': '#1e293b',
          },
          fontFamily: {
            inter: ['Inter', 'sans-serif'],
          },
        },
      }
    }
  </script>

  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .card-shadow {
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
      }
      .card-hover {
        transition: transform 0.3s ease, box-shadow 0.3s ease;
      }
      .card-hover:hover {
        transform: translateY(-5px);
        box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
      }


      .chart-container {
        height: 400px;
        width: 1400px;
      }
      .skeleton {
        background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
        background-size: 200% 100%;
        animation: skeleton-loading 1.5s infinite;
      }
      @keyframes skeleton-loading {
        0% { background-position: 200% 0; }
        100% { background-position: -200% 0; }
      }
    }
  </style>
</head>
<body class="bg-gray-50 font-inter text-gray-800 min-h-screen flex flex-col">
  <!-- 导航栏 -->
  <nav class="bg-white shadow-md sticky top-0 z-50 transition-all duration-300" id="navbar">
    <div class="container mx-auto px-4 py-3 flex justify-between items-center">
      <div class="flex items-center space-x-2">
        <i class="fa fa-line-chart text-primary text-2xl"></i>
        <h1 class="text-xl font-bold text-primary">广东城市房产数据可视化</h1>
      </div>
      <div class="hidden md:flex space-x-6">
        <a href="#overview" class="text-gray-600 hover:text-primary transition-colors">概览</a>
        <a href="#price" class="text-gray-600 hover:text-primary transition-colors">价格分析</a>
        <a href="../web/成交内容.html" class="text-gray-600 hover:text-primary transition-colors">成交房源</a>
        <a href="../web/在售内容.html" class="text-gray-600 hover:text-primary transition-colors">在售房源</a>
      </div>
      <button class="md:hidden text-gray-600 focus:outline-none" id="menu-toggle">
        <i class="fa fa-bars text-xl"></i>
      </button>
    </div>
  </nav>

  <!-- 主内容区 -->
  <main class="flex-grow container mx-auto px-4 py-8">
    <!-- 数据加载状态 -->
    <div id="loading" class="py-12 text-center">
      <div class="inline-block animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
      <p class="mt-4 text-gray-600">正在加载数据...</p>
    </div>

    <!-- 数据可视化区域 -->
    <div id="visualization" class="hidden">
      <!-- 概览区域 -->
      <section id="overview" class="mb-12">
        <div class="bg-white rounded-xl p-6 card-shadow">
          <h2 class="text-2xl font-bold mb-6 flex items-center">
            <i class="fa fa-globe text-primary mr-2"></i>城市数据概览
          </h2>

          <!-- 城市数据卡片 -->
          <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-8">
            <div class="bg-blue-50 rounded-lg p-4 card-shadow card-hover">
              <div class="flex justify-between items-start">
                <div>
                  <p class="text-sm text-gray-500">总房源数</p>
                  <h3 class="text-2xl font-bold mt-1" id="total-properties">0</h3>
                </div>
                <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center">
                  <i class="fa fa-home text-primary"></i>
                </div>
              </div>
            </div>

            <div class="bg-green-50 rounded-lg p-4 card-shadow card-hover">
              <div class="flex justify-between items-start">
                <div>
                  <p class="text-sm text-gray-500">平均单价</p>
                  <h3 class="text-2xl font-bold mt-1" id="avg-price">0</h3>
                </div>
                <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center">
                  <i class="fa fa-cny text-green-600"></i>
                </div>
              </div>
            </div>

            <div class="bg-yellow-50 rounded-lg p-4 card-shadow card-hover">
              <div class="flex justify-between items-start">
                <div>
                  <p class="text-sm text-gray-500">平均面积</p>
                  <h3 class="text-2xl font-bold mt-1" id="avg-area">0</h3>
                </div>
                <div class="w-10 h-10 rounded-full bg-yellow-100 flex items-center justify-center">
                  <i class="fa fa-arrows-alt text-yellow-600"></i>
                </div>
              </div>
            </div>

            <div class="bg-purple-50 rounded-lg p-4 card-shadow card-hover">
              <div class="flex justify-between items-start">
                <div>
                  <p class="text-sm text-gray-500">最多关注</p>
                  <h3 class="text-2xl font-bold mt-1" id="max-attention">0</h3>
                </div>
                <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center">
                  <i class="fa fa-eye text-purple-600"></i>
                </div>
              </div>
            </div>

            <div class="bg-red-50 rounded-lg p-4 card-shadow card-hover">
              <div class="flex justify-between items-start">
                <div>
                  <p class="text-sm text-gray-500">城市数量</p>
                  <h3 class="text-2xl font-bold mt-1" id="city-count">0</h3>
                </div>
                <div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center">
                  <i class="fa fa-map-marker text-red-600"></i>
                </div>
              </div>
            </div>
          </div>
        </div>

      </section>
      <section id="mmap" class="mb-12">
        <div class="bg-white rounded-xl p-6 card-shadow">
          <div class="mb-6">
            <h3 class="text-xl font-semibold mb-4">房源城市分布</h3>
            <div id="map-container" style="height: 500px;"></div>
        </div>
        </div>
      </section>


      <!-- 价格分析区域 -->
      <section id="price" class="mb-12">
        <div class="bg-white rounded-xl p-6 card-shadow">
          <h2 class="text-2xl font-bold mb-6 flex items-center">
            <i class="fa fa-money text-primary mr-2"></i>价格分析
          </h2>

          <!-- 价格分析选项卡 -->
          <div class="border-b mb-6">
            <div class="flex space-x-8">
              <button class="py-2 px-1 border-b-2 border-transparent font-medium text-gray-500 hover:text-primary tab-active" data-tab="price-city">城市对比</button>
              <button class="py-2 px-1 border-b-2 border-transparent font-medium text-gray-500 hover:text-primary" data-tab="price-area">面积与价格</button>
              <button class="py-2 px-1 border-b-2 border-transparent font-medium text-gray-500 hover:text-primary" data-tab="price-trend">价格区间</button>
            </div>
          </div>

          <!-- 价格分析图表 -->
          <div class="tab-content" id="price-city-content">
            <div class="chart-container" id="price-city-chart"></div>
          </div>
          <div class="tab-content hidden" id="price-area-content">
            <div class="chart-container" id="price-area-chart"></div>
          </div>
          <div class="tab-content hidden" id="price-trend-content">
            <div class="chart-container" id="price-trend-chart"></div>
          </div>
        </div>
      </section>
    </div>






  </main>

  <!-- 页脚 -->
  <footer class="bg-gray-800 text-white py-8">
    <div class="container mx-auto px-4">
      <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
        <div>
          <h3 class="text-lg font-bold mb-4">广东城市房产数据可视化</h3>
          <p class="text-gray-400">基于ECharts的数据可视化项目，展示广东省内各城市房产特征对比分析。</p>
        </div>
        <div>
          <h3 class="text-lg font-bold mb-4">数据来源</h3>
          <p class="text-gray-400">https://www.lianjia.com 链家网</p>
        </div>
        <div>
          <h3 class="text-lg font-bold mb-4">在售与成交</h3>
          <p class="text-gray-400"><a href="../web/成交内容.html">成交页面</a></p>
          <p class="text-gray-400"><a href="../web/在售内容.html">在售页面</a></p>
        </div>
      </div>
      <div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-500">
        <p>&copy; 2025 广东城市房产数据可视化</p>
      </div>
    </div>
  </footer>

  <script>

    // 导航栏滚动效果
    window.addEventListener('scroll', function() {
      const navbar = document.getElementById('navbar');
      if (window.scrollY > 20) {
        navbar.classList.add('py-2');
        navbar.classList.remove('py-3');
      } else {
        navbar.classList.add('py-3');
        navbar.classList.remove('py-2');
      }
    });

    // 选项卡切换
    document.querySelectorAll('[data-tab]').forEach(tab => {
      tab.addEventListener('click', function() {

        // 移除所有选项卡的活动状态
        document.querySelectorAll('[data-tab]').forEach(t => {
          t.classList.remove('tab-active');
        });

        // 添加当前选项卡的活动状态
        this.classList.add('tab-active');

        // 获取选项卡内容ID
        const tabId = this.getAttribute('data-tab');
        const contentId = tabId + '-content';

        // 隐藏所有内容
        document.querySelectorAll('.tab-content').forEach(content => {
          content.classList.add('hidden');
        });

        // 显示当前内容
        const currentContent = document.getElementById(contentId);
        if (currentContent) {
          currentContent.classList.remove('hidden');

          // 重新初始化图表（解决选项卡切换时图表不显示的问题）
          if (tabId === 'price-area' && priceAreaChart) {
            priceAreaChart.resize();
          }
        }
      });
    });

    // 加载CSV数据
    function loadCSVData() {
      return new Promise((resolve, reject) => {
        fetch('../data/zs/在售集合/广东在售二手房数据.csv')
          .then(response => {
            if (!response.ok) {
              throw new Error(`HTTP error! status: ${response.status}`);
            }
            return response.text();
          })
          .then(csvText => {
            // 解析CSV数据
            const rows = csvText.split('\n');
            const headers = rows[0].split(',');
            const data = [];

            for (let i = 1; i < rows.length; i++) {
              if (rows[i].trim() === '') continue;

              const values = rows[i].split(',');
              const obj = {};

              for (let j = 0; j < headers.length; j++) {
                // 处理数值类型，添加错误处理
                if (headers[j] === '单价' || headers[j] === '面积' || headers[j] === '关注人数' || headers[j] === '总价') {
                  // 检查是否为有效数值
                  const numValue = parseFloat(values[j]);
                  obj[headers[j]] = isNaN(numValue) ? 0 : numValue;
                } else {
                  obj[headers[j]] = values[j] || '未知';
                }
              }

              data.push(obj);
            }

            resolve(data);
          })
          .catch(error => {
            console.error('加载CSV数据失败:', error);
            reject(error);
          });
      });
    }

    // 初始化图表
    let priceAreaChart = null;

    function initCharts(data) {
      // 过滤掉无效数据
      const validData = data.filter(item => {
        return item['单价'] > 0 && item['面积'] > 0 && item['总价'] > 0;
      });

      // 更新统计数据
      document.getElementById('total-properties').textContent = validData.length;

      const totalPrice = validData.reduce((sum, item) => sum + item['单价'], 0);
      const avgPrice = totalPrice > 0 ? Math.round(totalPrice / validData.length) : 0;
      document.getElementById('avg-price').textContent = avgPrice + ' 元/㎡';

      const totalArea = validData.reduce((sum, item) => sum + item['面积'], 0);
      const avgArea = totalArea > 0 ? Math.round(totalArea / validData.length) : 0;
      document.getElementById('avg-area').textContent = avgArea + ' ㎡';

      document.getElementById('max-attention').textContent = Math.max(...validData.map(item => item['关注人数']));

      const cities = [...new Set(validData.map(item => item['城市']))];
      document.getElementById('city-count').textContent = cities.length;



      // 城市单价对比柱状图
      const priceCityChart = echarts.init(document.getElementById('price-city-chart'));
      const cityAvgPrice = {};

      validData.forEach(item => {
        if (cityAvgPrice[item['城市']]) {
          cityAvgPrice[item['城市']].sum += item['单价'];
          cityAvgPrice[item['城市']].count++;
        } else {
          cityAvgPrice[item['城市']] = { sum: item['单价'], count: 1 };
        }
      });

      const cityPriceData = Object.keys(cityAvgPrice).map(city => ({
        name: city,
        value: Math.round(cityAvgPrice[city].sum / cityAvgPrice[city].count)
      }));

      priceCityChart.setOption({
        title: {
          text: '各城市平均单价对比',
          left: 'center'
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: cityPriceData.map(item => item.name),
          axisLabel: {
            rotate: 45,
            interval: 0
          }
        },
        yAxis: {
          type: 'value',
          name: '单价 (元/㎡)'
        },
        series: [
          {
            name: '平均单价',
            type: 'bar',
            data: cityPriceData.map(item => item.value),
            color: '#3b82f6',
            label: {
              show: true,
              position: 'top',
              formatter: function(params) {
                return params.value.toLocaleString();
              }
            }
          }
        ]
      });

        // 面积与价格散点图
        priceAreaChart = echarts.init(document.getElementById('price-area-chart'));

        // 获取所有唯一城市
        const pcities = [...new Set(validData.map(item => item['城市']))];

        // 动态生成足够数量的颜色（使用HSL色系渐变）
        const generateColors = (count) => {
            const colors = [];
            for (let i = 0; i < count; i++) {
                // 色相环均匀分布，饱和度和亮度固定
                const hue = 360 * i / count;
                colors.push(`hsl(${hue}, 70%, 60%)`);
            }
            return colors;
        };

        const colorList = generateColors(pcities.length);
        const cityColorMap = {};
        pcities.forEach((city, index) => {
            cityColorMap[city] = colorList[index];
        });

        // 转换数据格式（包含城市颜色信息）
        const areaPriceData = validData.map(item => ({
            value: [item['面积'], item['总价']],
            city: item['城市'],
            color: cityColorMap[item['城市']]
        }));

        // 按城市分组数据并创建系列
        const citySeries = pcities.map(city => {
            return {
                name: city, // 使用城市名称作为系列名称
                type: 'scatter',
                data: areaPriceData
                    .filter(item => item.city === city)
                    .map(item => item.value), // 提取面积和总价数据
                symbolSize: 8,
                itemStyle: {
                    opacity: 0.7,
                    color: cityColorMap[city] // 使用对应城市的颜色
                }
            };
        });

        priceAreaChart.setOption({
            title: {
                text: '面积与总价关系（城市区分）',
                left: 'center'
            },
            tooltip: {
                trigger: 'item',
                formatter: function(params) {
                    const city = params.seriesName; // 从系列名称获取城市
                    const area = params.value[0];
                    const price = params.value[1];
                    return `城市: ${city}<br/>面积: ${area}㎡<br/>总价: ${price}万`;
                }
            },
            legend: {
                data: pcities,
                type: 'scroll', // 启用滚动模式，支持更多城市
                orient: 'horizontal',
                bottom: 10,
                left: 'center',
                pageIconColor: '#666',
                pageIconInactiveColor: '#ccc',
                itemWidth: 10,
                itemHeight: 10,
                textStyle: {
                    color: '#333',
                    fontSize: 10 // 缩小字体适应更多城市
                }
            },
            xAxis: {
                type: 'value',
                name: '面积 (㎡)'
            },
            yAxis: {
                type: 'value',
                name: '总价 (万)'
            },
            series: citySeries // 使用按城市分组的系列数组
        });


      // 价格区间分布直方图
        const priceTrendChart = echarts.init(document.getElementById('price-trend-chart'));
        const priceRangeData = {};
        validData.forEach(item => {
            let range = item['总价区间'].trim();
            range = range.replace('－', '-'); // 处理全角符号
            priceRangeData[range] = (priceRangeData[range] || 0) + 1;
        });

        const priceRangeKeys = ['50万以内', '50-100万', '100-200万', '200万以上'];
        const priceRangeValues = priceRangeKeys.map(range => priceRangeData[range] || 0);

        // 配置项
        priceTrendChart.setOption({
            title: {
                text: '总价区间分布',
                left: 'center'
            },
            tooltip: {
                trigger: 'axis',
                axisPointer: {
                    type: 'shadow'
                }
            },
            xAxis: {
                type: 'category',
                data: priceRangeKeys,
                axisLabel: {
                    interval: 0,
                    rotate: 30
                }
            },
            yAxis: {
                type: 'value',
                name: '房源数量',
                min: 0,
                axisLabel: {
                    formatter: '{value}'
                }
            },
            series: [
                {
                    name: '房源数量',
                    type: 'bar',
                    data: priceRangeValues,
                    label: {
                        show: true,
                        position: 'top',
                        formatter: '{c}'
                    },
                    itemStyle: {
                        borderRadius: [5, 5, 0, 0]
                    },
                    barWidth: '40%'
                }
            ],
            grid: {
                left: '3%',
                right: '4%',
                bottom: '10%',
                top: '15%',
                containLabel: true
            }
        });
        priceTrendChart.resize();

        // 加载广东地图数据
        fetch('../static/js/广东省.json')
          .then(response => response.json())
          .then(guangdongJson => {
            // 注册广东地图
            echarts.registerMap('广东', guangdongJson);

            // 广东省地图
            const mapChart = echarts.init(document.getElementById('map-container'));
            const cityCount1 = {};

            validData.forEach(item => {
              if (cityCount1[item['城市']]) {
                cityCount1[item['城市']]++;
              } else {
                cityCount1[item['城市']] = 1;
              }
            });

            // 将城市计数对象转换为数组格式
            const mapData = Object.keys(cityCount1).map(city => ({
              name: city + '市', // 添加"市"后缀以匹配地图上的城市名称
              value: cityCount1[city]
            }));

            mapChart.setOption({
              title: {
                text: '广东各城市房源分布',
                left: 'center',
                textStyle: {
                  fontSize: 18,
                  fontWeight: 'bold',
                  color: '#333'
                }
              },
              tooltip: {
                trigger: 'item',
                formatter: function(params) {
                  return `<div style="color:#333; font-size:14px;">
                            <strong>${params.name}</strong><br>
                            房源数量: ${params.value}套
                          </div>`;
                },
                backgroundColor: 'rgba(255, 255, 255, 0.9)',
                borderColor: '#ccc',
                borderWidth: 1,
                padding: 10,
                extraCssText: 'box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);'
              },
              visualMap: {
                min: 0,
                max: Math.max(...mapData.map(item => item.value)),
                text: ['高', '低'],
                type: 'piecewise', // 分段式视觉映射
                orient: 'horizontal',
                left: 'center',
                bottom: 10,
                inRange: {
                  color: ['#e0f3f8', '#a3dced', '#3c8dbc'] // 渐变颜色
                },
                textStyle: {
                  fontSize: 12,
                  color: '#333'
                }
              },
              series: [
                {
                  name: '房源数量',
                  type: 'map',
                  map: '广东',
                  roam: true,
                  label: {
                    show: true,
                    fontSize: 12,
                    color: '#333',
                    formatter: function(params) {
                      return params.name.replace('市', ''); // 移除“市”后缀
                    }
                  },
                  itemStyle: {
                    areaColor: '#e0f3f8',
                    borderColor: '#444',
                    borderWidth: 0.5
                  },
                  emphasis: {
                    itemStyle: {
                      areaColor: '#a3dced'
                    }
                  },
                  data: mapData
                }
              ]
            });
            // 响应式处理
            window.addEventListener('resize', function() {
              mapChart.resize();
            });
          })
          .catch(error => {
            console.error('加载广东地图数据失败:', error);
          });




      // 响应式处理
      window.addEventListener('resize', function() {
        priceCityChart.resize();
        if (priceAreaChart) priceAreaChart.resize();
        if (priceTrendChart) priceTrendChart.resize();
      });
    }

    // 页面加载完成后执行
    document.addEventListener('DOMContentLoaded', function() {
      loadCSVData()
        .then(data => {
          // 隐藏加载状态，显示可视化内容
          document.getElementById('loading').classList.add('hidden');
          document.getElementById('visualization').classList.remove('hidden');

          // 初始化图表
          initCharts(data);
        })
        .catch(error => {
          console.error('加载数据失败:', error);
          document.getElementById('loading').innerHTML = `
            <div class="text-red-500">
              <i class="fa fa-exclamation-triangle text-3xl mb-4"></i>
              <p class="text-lg">数据加载失败</p>
              <p class="text-sm mt-2">请确保数据文件路径正确且格式符合要求</p>
            </div>
          `;
        });
    });
  </script>
</body>
</html>
